﻿using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Xml;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
namespace BIN
{
    public partial class FrmUpdate : Form
    {
        private int _copiedFileCount = 0;
        private bool IsMainProgRuned = false;
        private bool isMainProgKilled = false;
        private string updateUrl = string.Empty;
        private string tempUpdatePath = string.Empty;//临时更新文件的目录
        private string tempDir = string.Empty; // temp目录
        private  XmlFiles updaterXmlFiles = null;//本地配置文件对象
        private int availableUpdate = 0; //可更新的文件
        private int fileCountDownloaded = 0; //已经下载的更新文件
        private string MainAppExe = "", _ProgName = "";
        private bool _AllKeyUptWasOK= false;
        private string localXmlFile = string.Empty;
        private string serverXmlFile = string.Empty;
        private AppUpdater appUpdater = null;
        private string AppDir = string.Empty;
        private WinServiceOp _serviceOp = null;
        private string _ShortConfigName = "UpdateList.xml";
        //以下是三种更新模式
        private bool _IsCopyFolderMode = false;
        private bool _IsDelayUpdateMode = false;
        private bool _IsSilentMode = false;
        private NotifyIcon _ntyIcon = null;
        private event EventHandler OnFileDownloaded;
        private string _restartAlert = string.Empty;
        private DateTime? _startUpdateTime = null;
        private const int RESTART_WAIT_SECOND = 30; //等待多少秒就自动杀主进程
        private const int CONFIRM_UPTTIME_BIG = 5; //更新少于多少秒就不采用CONFIRM模式

        public string ShortConfigName
        {
            get { return _ShortConfigName; }
            set { _ShortConfigName = value; }
        }
        /// <summary>
        /// 下载了一个文件
        /// </summary>
        private void DownLoaded1File()
        {
            ++fileCountDownloaded;
            if (null != OnFileDownloaded) OnFileDownloaded(this, null);
        }
        /// <summary>
        /// 是否是静默模式的更新
        /// </summary>
        /// <returns></returns>
        private bool IsSilentMode()
        {
            bool Ret = ShareMet.CallFromMainProg
                && AppUpdater.SilentMode;
            AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Is silent Updating ? {0}",
                Ret ? "Yes" : "No"));
            return Ret;
        }
        /// <summary>
        /// 是否是复制目录的更新方式
        /// </summary>
        private bool IsCopyFolderUpdating()
        {
            bool Ret= ShareMet.CallFromMainProg 
                && AppUpdater.RewakeUpdateMode 
                && ShareMet.FileExists(serverXmlFile)
                && System.IO.Directory.Exists(tempUpdatePath) ;
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Is Copy Folder Updating ? {0}",
                Ret ? "Yes" : "No"));
            return Ret;
        }
        private bool IsDelayUpdateMode()
        {
            bool Ret = ShareMet.CallFromMainProg
                  && AppUpdater.RewakeUpdateMode ;
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Is Delay Updating ? {0}",
                Ret ? "Yes" : "No"));
            return Ret;
        }
        public FrmUpdate()
        {
            InitializeComponent();
            FrmUpdate.CheckForIllegalCrossThreadCalls = false;
            _startUpdateTime = DateTime.Now;
            AppDir = AppDomain.CurrentDomain.BaseDirectory;
            tempDir = ShareMet.CombineDir(AppDir, "temp");
            tempUpdatePath = ShareMet.CombineDir(tempDir, "Downloads\\");
            //服务端配置文件下载到本地
            serverXmlFile = ShareMet.CombineDir(tempDir, this.ShortConfigName);
            _IsSilentMode = IsSilentMode();
            if (!_IsSilentMode)
            {
                //是否是目录复制模式
                _IsCopyFolderMode = IsCopyFolderUpdating();
                //是否是延迟更新模式
                if (!_IsCopyFolderMode)
                {
                    _IsDelayUpdateMode = IsDelayUpdateMode();
                }
            }
            else
            {
                this.OnFileDownloaded += new EventHandler(FrmUpdate_OnFileDownloaded);
            }
            //取本地配置文件
            localXmlFile = ShareMet.CombineDir(AppDir, this.ShortConfigName);
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, DateTime.Now.ToString() + " ,start updating...");
            if (!(System.IO.File.Exists(localXmlFile))) //不存在配置文件
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, "File " + localXmlFile + "doesn't exist ,You can use (*.EXE) /NOUPDATE to start the program!");
                ExitUpdateProg();
                return;
            }
            //从本地读取更新配置文件信息
            updaterXmlFiles = new XmlFiles(localXmlFile);
            //
            MainAppExe = GetMainProgExe();
            if (MainAppExe == "")
            {
                string info="Error occurs when getting main program from config file,Please check <EntryPoint>...</EntryPoint> in updatelist.xml!";
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.WARN,info );
                throw new Exception(info);
            }
            _ProgName = MainAppExe.ToUpper().Replace(".EXE", "");
            _restartAlert = string.Format("{0} will restart in {1} seconds", _ProgName, RESTART_WAIT_SECOND);
            IsMainProgRuned = IsMainAppRun();
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Main prog was runned ? {0} ", IsMainProgRuned));
            if (AppUpdater.CheckOpService)
            {
                _serviceOp = new WinServiceOp();
                _serviceOp.OnServiceStatusChanged +=
                    new WinServiceOp.ServiceStatusChangeHandler(_serviceOp_OnServiceStatusChanged);
            }
            try
            {
                if (!_IsCopyFolderMode)
                {
                    Init();
                }
            }
            catch (Exception ex)
            {
                 BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                ExitUpdateProg();
            }
        }
        /// <summary>
        /// 成功下载了文件时的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void FrmUpdate_OnFileDownloaded(object sender, EventArgs e)
        {
            if (null != _ntyIcon && _IsSilentMode)
            {
                _ntyIcon.Text = string.Format("Downloading {0} / {1}", fileCountDownloaded, availableUpdate);
            }
        }
        void _serviceOp_OnServiceStatusChanged(object sender, ServiceEventArgs e)
        {
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("!!!!!Success starting {0} service [{1}]!!!!!",
                e.Status == SERVICE_STATUS.START ? "Start" : "Stop",
                e.ServiceDesc));
        }
        private string GetFileFix(string fixPath, string FullPath)
        {
            int index = FullPath.IndexOf(fixPath);
            if (index < 0) return FullPath;
            return FullPath.Substring(index+fixPath.Length , FullPath.Length - fixPath.Length );
        }
        private void Init()
        {
            btnFinish.Visible = false;
            string dir = System.IO.Path.Combine(AppDir, "Logs");
            if (!(System.IO.Directory.Exists(dir))) 
                System.IO.Directory.CreateDirectory(dir);
            try
            {
                appUpdater = new AppUpdater();
                appUpdater.ShortConfigName = this.ShortConfigName;
                appUpdater.AppDir = AppDir;
                if (updaterXmlFiles.GetNodeValue(
                    "//NeedUpdate").Trim().Equals("NO", StringComparison.OrdinalIgnoreCase ))
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "No updating necessary(configged),exit.");
                    ExitUpdateProg();
                    return;
                }
                //获取服务器地址
                if (ShareMet.IsUpdateAgent)
                {
                    updateUrl = appUpdater.GetUpdateRootUrl(updaterXmlFiles);
                    if (string.Empty.Equals(updateUrl, StringComparison.OrdinalIgnoreCase))
                    {
                        updateUrl = appUpdater.GetUpdateUrl(updaterXmlFiles);
                    }
                    else
                    {
                        appUpdater.FillLimitKey(AppUpdater.DownloadTempDir);
                    }
                }
                else
                {
                    updateUrl = appUpdater.GetUpdateUrl(updaterXmlFiles);
                }
                if ( string.IsNullOrEmpty( updateUrl))
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.WARN, "Get url error from local config file!,Please check <Url>http://remotehost_ip/</Url>");
                    ExitUpdateProg();
                    return;
                }
                else
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, string.Format("Update from url '{0}'!", updateUrl));
                }
                //这里就已经取到了服务端设置的LimitKey
                try
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                        string.Format("LimitKey is :{0},Local UpdateKey is:{1},But It's autoupate.exe(not updatesilent.exe),so,Continue updating!",
                        appUpdater.LimitKey, ShareMet.UpdateKey));
                }
                catch (Exception ex)
                {
                    appUpdater.WriteException(ex);
                }
                if (appUpdater.CurrPointWasLimited())
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.WARN,
                        "Updating was not allowwed!");
                    ExitUpdateProg();
                }
                if (updateUrl.EndsWith(@"/") || updateUrl.EndsWith(@"\"))
                    appUpdater.UpdaterUrl = updateUrl + this.ShortConfigName;
                else
                {
                    if (updateUrl.StartsWith(@"\\"))
                        appUpdater.UpdaterUrl = updateUrl + @"\" + this.ShortConfigName;
                    else
                        appUpdater.UpdaterUrl = updateUrl + @"/" + this.ShortConfigName;
                }
                //下载服务端的配置文件
                if (!(ShareMet.UpdateListFileIsOk(ShareMet.CombineDir(tempUpdatePath, this.ShortConfigName))))
                {
                    appUpdater.DownAutoUpdateFile(tempDir);
                }
            }
            catch
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, "Syntax error.(" + appUpdater.UpdaterUrl + ")");
                ExitUpdateProg();
                return;
            }
            //获取更新文件列表
            Hashtable htUpdateFile = new Hashtable();
            try
            {
                if (!File.Exists(serverXmlFile))
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, "Error occurs when saving server config file " + serverXmlFile + " to local!");
                    ExitUpdateProg();
                    return;
                }
                availableUpdate = appUpdater.CheckForUpdate(serverXmlFile, localXmlFile, out htUpdateFile);
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                    string.Format("available update file count: {0}!", availableUpdate));
                if (availableUpdate > 0)
                {
                    //下载时不杀死主程序bin
                    /*
                    if (IsMainProgRuned)
                    {
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                            "Main prog was runned ,try to kill...");
                        KillMainProg();
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                            "Kill finished!");
                    }
                    */
                    for (int i = 0; i < htUpdateFile.Count; i++)
                    {
                        string[] fileArray = (string[])htUpdateFile[i];
                        lvUpdateList.Items.Add(new ListViewItem(fileArray));
                    }
                }
                else
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "No updating necessary!");
                    if (null != appUpdater)
                    {
                        if (appUpdater.ServerConfigIsNewer())
                        {
                            File.Copy(serverXmlFile, localXmlFile, true);
                        }
                    }
                    ExitUpdateProg();
                    return;
                }

            }
            catch(Exception ex)
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                ExitUpdateProg();
                return;
            }
        }
        private void FrmUpdate_Load(object sender, System.EventArgs e)
        {
            this.Text = _ProgName;
            lblCaption.Text = string.Format("{0} updater", _ProgName);
            if (_IsSilentMode)//静默模式不显示窗体
            {
                this.ShowInTaskbar = false;
                this.Hide();
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                    "It's silent mode , hide self!");
                try
                {
                    if (null != this.components)
                    {
                        _ntyIcon = new NotifyIcon(this.components);
                    }
                    else
                    {
                        _ntyIcon = new NotifyIcon();
                    }
                    _ntyIcon.Visible = true;
                    _ntyIcon.Icon = Properties.Resources.down;
                    _ntyIcon.BalloonTipTitle = _ProgName;
                    _ntyIcon.MouseDoubleClick += new MouseEventHandler(_ntyIcon_MouseDoubleClick);
                }
                catch { }
            }
            if (!_IsCopyFolderMode)
            {
                if (availableUpdate > 0)
                {
                    this.Invoke(new Action(delegate
                    {
                        btnNext.Visible = true;
                        btnNext.Enabled = true;
                        doNext();
                    }));
                }
            }
            else//目录复制模式直接从临时文件中复制
            {
                this.Invoke(new Action(delegate
                {
                    doFinish();
                 }));
            }
        }

        void _ntyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (!this.Visible)
            {
                this.Show();
                this.ShowInTaskbar = true;
            }
            else
            {
                this.ShowInTaskbar = false;
                this.Hide();
            }
        }
        /// <summary>
        /// 延迟更新模式不能删除文件_IsDelayUpdateMode=true
        /// </summary>
        private void DelTempDir()
        { 
            try
            {
                if (System.IO.Directory.Exists(tempUpdatePath) && !_IsDelayUpdateMode)
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                        string.Format("Delete directory:{0}", tempUpdatePath));
                    System.IO.Directory.Delete(tempUpdatePath, true);
                }
                else
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                        string.Format("No necessary to delete directory:{0},It's empty or delay updating mode!",
                        tempUpdatePath));
                }
            }
            catch { }
            try
            {
                if (ShareMet.FileExists(serverXmlFile) && ( !_IsDelayUpdateMode || 0==availableUpdate ))
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                        string.Format("Delete configfile:{0}", serverXmlFile));
                    System.IO.File.Delete(serverXmlFile);
                }
                else
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                           string.Format("No necessary to delete file:{0},It doesn't exists or delay updating mode!",
                           serverXmlFile));
                }
            }
            catch { }
        }
        private void ExitUpdateProg()
        {
            DelTempDir();
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Is main prog killed ? {0}", isMainProgKilled));
            if (ShareMet.CallFromMainProg && isMainProgKilled)
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                    "But I called from main prog,so still start main prog");
            }
            if (isMainProgKilled || ShareMet.CallFromMainProg || _IsSilentMode)
            {
                StartMainProgNoUpdate();
            }
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,"Execute exit invoking! ");
           Environment.Exit(0);
        }
        private void btnCancel_Click(object sender, System.EventArgs e)
        {
            ExitUpdateProg();
        }
        private void btnNext_Click(object sender, System.EventArgs e)
        {
            doNext();
        }
        private void doNext()
        { 
            btnNext.Visible = false;
            if (availableUpdate > 0)
            {
                Thread threadDown = new Thread(new ThreadStart(DownUpdateFile));
                threadDown.IsBackground = true;
                threadDown.Start();
            }
            else
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "No updating necessary!");
                ExitUpdateProg();
                return;
            }
        }
        private string GetMainProgExe()
        {
            string ret = AppUpdater.FixxedProgName;
            if (string.Empty.Equals(ret))
            {
                ret = (updaterXmlFiles.GetNodeValue("//EntryPoint"));
            }
          BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
              string.Format("Main prog is :{0}!", ret));
          return ret;
        }
        private void StartMainProgNoUpdate()
        {
            try
            {
                if (!isMainProgKilled ) return;
                string Cmd = string.Format( "{0}", 
                   ShareMet.CombineDir( AppDir  , MainAppExe));
                AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                    string.Format("Start main prog '{0}' /NOUPDATE ", Cmd));
                System.Diagnostics.ProcessStartInfo startInfo =
                    new ProcessStartInfo(Cmd, @" /NOUPDATE");
                Process.Start(startInfo );
            }
            catch(Exception ex)
            {
                if (!_IsSilentMode)
                {
                    MessageBox.Show(ex.Message, "AutoUpdate");
                }
            }
        }
        private void StartSpecifiedProgNoUpdate(string ShortProgName)
        {
            try
            {
                if (!isMainProgKilled) return;
                string Cmd = string.Format("{0}",
                   ShareMet.CombineDir(AppDir, ShortProgName));
                AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                    string.Format("Start main prog '{0}' /NOUPDATE ", Cmd));
                System.Diagnostics.ProcessStartInfo startInfo =
                    new ProcessStartInfo(Cmd, @" /NOUPDATE");
                Process.Start(startInfo);
            }
            catch (Exception ex)
            {
                if (!_IsSilentMode)
                {
                    MessageBox.Show(ex.Message, "AutoUpdate");
                }
            }
        }
        private void KillMainProg()
        {
            //isMainProgKilled= ShareMet.ProgRunned(MainAppExe, true);
            Process[] allProcess = Process.GetProcesses();
            foreach (Process p in allProcess)
            {
                string proName = p.ProcessName + ".exe";
                bool matched=proName.Equals( MainAppExe, StringComparison.OrdinalIgnoreCase);
                if (!matched && !string.IsNullOrEmpty( AppUpdater.AlsoKillProg) )
                {
                    string[] progArr = AppUpdater.AlsoKillProg.Split(new char[] {',',';' },
                        StringSplitOptions.RemoveEmptyEntries);
                    if (null != progArr && 0 < progArr.Length)
                    {
                        foreach (string prog in progArr)
                        {
                            matched = proName.Equals(prog,StringComparison.OrdinalIgnoreCase);
                            if (matched)
                            {
                                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                                    string.Format("It will also kill Program {0} !", prog));
                            }
                        }
                    }
                }
                if (matched )
                {
                    for (int i = 0; i < p.Threads.Count; i++)
                        p.Threads[i].Dispose();
                    p.Kill();
                    isMainProgKilled = true;
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                        string.Format("Kill Program {0} !", proName));
                }
            }
            if (AppUpdater.YsPosMode)
            {
                ShareMet.ProgRunned("ShowMessage.exe", true);
                ShareMet.ProgRunned("Poscmd.exe", true);
                ShareMet.ProgRunned("Patch_Pos.exe", true);
                ShareMet.ProgRunned("AttendRecording.exe", true);
                ShareMet.ProgRunned("CashForwardManual.exe", true);
                ShareMet.ProgRunned("Patching.exe", true);
                ShareMet.ProgRunned("SyncUI.exe", true);
                ShareMet.ProgRunned("YSPOSTools.exe", true);
                Thread.Sleep(500);
            }
            else
            {
                ShareMet.ProgRunned("BIRpt.exe", true);
            }
            if (isMainProgKilled) Thread.Sleep(500);
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Main prog is killed :{0}!",
                isMainProgKilled));
        }
        private void DownUpdateFile()
        { 
            if  (AppUpdater.PartialDowning)
                DownUpdateFilePart();
            else
                DownUpdateFileWhole();
        }
        private void DownUpdateFilePart()
        {
            WebClient wcClient = null;
            WebRequest webReq = null;
            WebResponse webRes = null;
            this.Cursor = Cursors.WaitCursor;
            ListViewItem lv = null;
            string KeyUptDesc = "";
            try
            {
                wcClient = new WebClient();
                if (!updateUrl.StartsWith("ftp:", StringComparison.OrdinalIgnoreCase))
                {
                    wcClient.UseDefaultCredentials = true;
                }
                for (int i = 0; i < this.lvUpdateList.Items.Count; i++)
                {
                    string UpdateFile = lvUpdateList.Items[i].Text.Trim();
                    if(AppUpdater.CheckOpService) _serviceOp.CheckFile(UpdateFile);
                    string updateFileUrl = updateUrl + lvUpdateList.Items[i].Text.Trim();
                    lv = lvUpdateList.Items[i];
                    KeyUptDesc = lv.SubItems[3].Text;
                    long fileLength = 0;
                    try
                    {
                        webReq = WebRequest.Create(updateFileUrl);
                        webRes = webReq.GetResponse();
                        webReq.Timeout = 500000;
                        fileLength = webRes.ContentLength;
                        lbState.Text = "Downloading the update file, please wait...";
                        pbDownFile.Value = 0;
                        pbDownFile.Maximum = (int)fileLength;
                        string tempPath = string.Empty;
                        Stream srm = null;
                        StreamReader srmReader = null;
                        FileStream fs =null;
                        try
                        {
                            srm = webRes.GetResponseStream();
                            srmReader = new StreamReader(srm);
                            byte[] bufferbyte = new byte[fileLength];
                            int allByte = (int)bufferbyte.Length;
                            int startByte = 0;
                            while (fileLength > 0)
                            {
                                Application.DoEvents();
                                int downByte = srm.Read(bufferbyte, startByte, allByte);
                                if (downByte == 0) break;
                                startByte += downByte;
                                allByte -= downByte;
                                pbDownFile.Value += downByte;
                                float part = (float)startByte / 1024;
                                float total = (float)bufferbyte.Length / 1024;
                                int percent = Convert.ToInt32((part / total) * 100);
                                this.lvUpdateList.Items[i].SubItems[2].Text = percent.ToString() + "%";
                            }
                            tempPath = tempUpdatePath + UpdateFile;
                            CreateDirtory(tempPath);
                            fs = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.Write);
                            fs.Write(bufferbyte, 0, bufferbyte.Length);
                        }
                        finally
                        {
                            srm.Close();
                            srmReader.Close();
                            fs.Close();
                            fs.Dispose();
                            srm.Dispose();
                            srmReader.Dispose();
                            srm = null;
                            srmReader = null;
                            fs = null;
                        }
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "downloading to " + tempPath + " ... ,OK!");
                        DownLoaded1File();
                    }
                    catch (Exception ex) //捕获一般性错误，如果是关键更新错误，则再抛出
                    {
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                        string ErrorText = "";
                        if (KeyUptDesc == "Y") //关键更新错误
                        {
                            _AllKeyUptWasOK = false;
                            ErrorText = string.Format("Error occurs when downloading key file'{0}'(Failure updating) ,exit", UpdateFile);
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ErrorText);
                            ExitUpdateProg();
                            if (isMainProgKilled) StartMainProgNoUpdate();
                            return;
                        }
                        else
                        {
                            this.lvUpdateList.Items[i].SubItems[2].Text = "FAIL";
                            ErrorText = string.Format("Error occurs when downloading non key file '{0}',(ignore),continue...", UpdateFile);
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.WARN, ErrorText);
                            continue;
                        }
                    }
                }
                lbState.Text = "All files downloaded completely!";
                _AllKeyUptWasOK = true;
                if (_AllKeyUptWasOK)
                {
                    if (AppUpdater.AutoFinish)
                    {
                        this.Invoke(new SimpleDo(delegate
                        {
                            doFinish();
                        }));
                    }
                }
                InvalidateControl();
            }
            catch (WebException ex)
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                btnCancel.Visible = true;
                btnCancel.Enabled = true;
                btnFinish.Visible = false;
                btnNext.Visible = false;
                ExitUpdateProg();
                if (isMainProgKilled) StartMainProgNoUpdate();
            }
            finally
            {
                if (null != wcClient)
                {
                    wcClient.Dispose();
                    wcClient = null;
                }
                this.Cursor = Cursors.Default;
            }
        }
        private void DownUpdateFileWhole()
        {
            WebClient wcClient = null;
            this.Cursor = Cursors.WaitCursor;
            ListViewItem lv = null;
            string KeyUptDesc = "";
            try
            {
                int FileCount = this.lvUpdateList.Items.Count;
                pbDownFile.Maximum = FileCount;
                pbDownFile.Value = 0;
                wcClient = new WebClient();
                if (!updateUrl.StartsWith("ftp:", StringComparison.OrdinalIgnoreCase))
                {
                    wcClient.UseDefaultCredentials = true;
                }
                for (int i = 0; i < FileCount; i++)
                {
                    string UpdateFile = lvUpdateList.Items[i].Text.Trim();
                    string tempPath = tempUpdatePath + UpdateFile;
                    if (AppUpdater.CheckOpService) _serviceOp.CheckFile(UpdateFile);
                    string updateFileUrl = updateUrl + UpdateFile;
                    lv = lvUpdateList.Items[i];
                    KeyUptDesc = lv.SubItems[3].Text;
                    try
                    {
                        ShareMet.CheckDownUrl(ref updateFileUrl, ref tempPath);
                        CreateDirtory(tempPath);
                        wcClient.DownloadFile(updateFileUrl, tempPath);
                        pbDownFile.Value++;
                        this.lvUpdateList.Items[i].SubItems[2].Text = "OK!";
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "Download to " + tempPath + " ... ,OK!");
                    }
                    catch (Exception ex) //捕获一般性错误，如果是关键更新错误，则再抛出
                    {
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                        string ErrorText = "";
                        if (KeyUptDesc == "Y") //关键更新错误
                        {
                            _AllKeyUptWasOK = false;
                            ErrorText = string.Format("Error occurs when downloading key file'{0}'(Failure updating) ,exit", UpdateFile);
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ErrorText);
                            ExitUpdateProg();
                            if (isMainProgKilled) StartMainProgNoUpdate();
                            return;
                        }
                        else
                        {
                            this.lvUpdateList.Items[i].SubItems[2].Text = "Fail";
                            ErrorText = string.Format("Error occurs when downloading non key file '{0}',(ignore),continue...", UpdateFile);
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.WARN, ErrorText);
                            continue;
                        }
                    }
                }
                _AllKeyUptWasOK = true;
                if (_AllKeyUptWasOK)
                {
                    if (AppUpdater.AutoFinish)
                    {
                        this.Invoke(new SimpleDo(delegate
                        {
                            doFinish();
                        }));
                    }
                }
                InvalidateControl();
            }
            catch (WebException ex)
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                btnCancel.Visible = true;
                btnCancel.Enabled = true;
                btnFinish.Visible = false;
                btnNext.Visible = false;
                ExitUpdateProg();
                if (isMainProgKilled) StartMainProgNoUpdate();
            }
            finally
            {
                this.Cursor = Cursors.Default;
                if (null != wcClient)
                {
                    wcClient.Dispose();
                }
            }
        }
        //创建目录
        private void CreateDirtory(string path)
        {
            if (!File.Exists(path))
            {
                string[] dirArray = path.Split('\\');
                string temp = string.Empty;
                for (int i = 0; i < dirArray.Length - 1; i++)
                {
                    temp += dirArray[i].Trim() + "\\";
                    if (!Directory.Exists(temp))
                    {
                        Directory.CreateDirectory(temp);
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "Create folder " + temp + " ... ,OK!");
                    }
                }
            }
        }
        
        //复制文件;
        public void CopyFile(string sourcePath, string objPath)
        {
            string oriFile = "",renTo="",fileFix="";
            string txt = "";
            if (!Directory.Exists(objPath))
            {
                Directory.CreateDirectory(objPath);
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "Create folder " + objPath + "... ,OK!");
            }
            string[] files = Directory.GetFiles(sourcePath);
            string tmpfile = "";
            for (int i = 0; i < files.Length; i++)
            {
                string[] childfile = files[i].Split('\\');
                oriFile = childfile[childfile.Length - 1];
                if (oriFile.EndsWith(".tmp")) continue;
                tmpfile = oriFile;
                if (tmpfile.Equals("AUTOUPDATE.EXE", StringComparison.OrdinalIgnoreCase)
                    || tmpfile.Equals("UPDATELIB.DLL", StringComparison.OrdinalIgnoreCase) ) continue;
                if (!_IsDelayUpdateMode)
                {
                    fileFix = GetFileFix(tempUpdatePath, files[i]);
                    renTo = appUpdater.FileRenameTo(fileFix);
                    childfile = renTo.Split('\\');
                    renTo = childfile[childfile.Length - 1];
                }
                txt = ShareMet.CombineDir(objPath, oriFile);
                File.Copy(files[i],txt  , true); //原文件名也复制一次
                ++_copiedFileCount;
                if ( ""!=renTo && !_IsDelayUpdateMode )
                {
                    txt = ShareMet.CombineDir( objPath , renTo );
                    File.Copy(files[i], txt, true);
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                      string.Format("Execute rename operating,'{0}'==>'{1}'!",
                      files[i], txt));
                    ++_copiedFileCount;
                }
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "Copy file " + files[i] + " --> " + txt);
            }
            string[] dirs = Directory.GetDirectories(sourcePath);
            for (int i = 0; i < dirs.Length; i++)
            {
                string[] childdir = dirs[i].Split('\\');
                txt= objPath + @"\" + childdir[childdir.Length - 1] ;
                CopyFile(dirs[i],txt );
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "Copy File " + dirs[i] + " -->" + txt);
            }
        }
        //点击完成复制更新文件到应用程序目录
        private void btnFinish_Click(object sender, System.EventArgs e)
        {
            doFinish();
        }
        private void doFinish()
        {
            DateTime curr = DateTime.Now;
            int updateSeconds= (int)(Math.Abs( ShareMet.DateDiff(DATEPART.SECOND,curr,_startUpdateTime.Value)));
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("It used {0} seconds to download the files!",updateSeconds));
            if(updateSeconds<=CONFIRM_UPTTIME_BIG)
            {
              BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                  string.Format("updating time less then {0} seconds,no confirm necessary!",CONFIRM_UPTTIME_BIG ));
            }
            if (_IsSilentMode && updateSeconds>CONFIRM_UPTTIME_BIG)
            {
                doFinishConfirm();
            }
            else
            {
                doFinishNormal();
            }
        }
        private int _waitedSeconds = 0;
        private bool _shifted = false;
        private void calc()
        {
            while (_waitedSeconds < RESTART_WAIT_SECOND)
            {
                System.Threading.Thread.Sleep(1000);
                ++_waitedSeconds;
                if (_waitedSeconds > 5 && !_shifted)
                {
                    _restartAlert = string.Format("Restart {0} immediately!", _ProgName);
                }
                this.Invoke(new Action(delegate
                {
                    btnRestartMain.Text =
                        string.Format("{0} {1}", _restartAlert, RESTART_WAIT_SECOND - _waitedSeconds);
                }));
            }
        }
        private void doFinishConfirm()
        {
            this.ShowInTaskbar = true;
            this.Show();
            Application.DoEvents();
            btnCancel.Visible = false;
            btnFinish.Visible = false;
            btnNext.Visible = false;
            btnRestartMain.Visible = true;
            this.TopMost = true;
            new MyThreadPool(this, calc, doFinishNormal, true);
        }
        private void doFinishNormal()
        {
            try
            {
                if (!_IsDelayUpdateMode)
                {
                    if (!_AllKeyUptWasOK && !_IsCopyFolderMode && !_IsDelayUpdateMode)
                    {
                        string info = "Error occurs when updating key file,Update failed!";
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, info);
                        throw new Exception(info);
                    }
                    else
                    {
                        //延迟模式不杀主进程
                        if (IsMainProgRuned)
                        {
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                                "Main prog was runned ,try to kill...");
                            KillMainProg();
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                                "Kill finished!");
                            Thread.Sleep(100);
                        }
                        try
                        {
                            if (AppUpdater.CheckOpService && null != _serviceOp) _serviceOp.StopService();
                            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                                string.Format("Begin copy folder...{0}=>{1}",
                                tempUpdatePath, AppDir));
                            CopyFile(tempUpdatePath, AppDir);
                            if (0 < _copiedFileCount)
                            {
                                if (ShareMet.FileExists(serverXmlFile))
                                {
                                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                                        string.Format("Begin copy config file...{0}=>{1}",
                                        serverXmlFile, localXmlFile));
                                    System.IO.FileInfo fi = new System.IO.FileInfo(serverXmlFile);
                                    if (fi.Exists && fi.Length > 1.0)
                                    {
                                        fi.CopyTo(localXmlFile, true);
                                        fi = null;
                                    }
                                }
                            }
                            Thread.Sleep(200);
                        }
                        finally
                        {
                            if (AppUpdater.CheckOpService && null != _serviceOp) _serviceOp.StartService();
                        }
                        if (ShareMet.IsUpdateAgent)
                        {
                            if (ShareMet.ShareFolder != "")
                            {
                                XmlFiles obj = new XmlFiles(localXmlFile);
                                System.Xml.XmlNodeList lst = obj.GetNodeList("//Url");
                                if (null != lst && lst.Count > 0)
                                {
                                    lst[0].Value = ShareMet.ShareFolder;
                                    obj.Save();
                                }
                                obj = null;
                            }
                        }
                        if (!_IsDelayUpdateMode)
                        {
                            System.IO.Directory.Delete(tempUpdatePath, true);
                        }
                        BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO, "Update success!");
                    }
                }
                else
                {
                    BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                        "It's deley updating mode,exit autoupdate directly!");
                }
            }
            catch (Exception ex)
            {
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, ex.Message);
                BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.ERROR, "Update failed!");
            }
            finally
            {
                ExitUpdateProg();
            }
        }
        //重新绘制窗体部分控件属性
        private void InvalidateControl()
        {
            this.Invoke(new SimpleDo(delegate {
                btnNext.Visible = false;
                btnCancel.Visible = false;
                btnFinish.Location = btnCancel.Location;
                btnFinish.Visible = true;
            } ));
        }
        //判断主应用程序是否正在运行
        private bool IsMainAppRun()
        {
            bool Ret= (ShareMet.ProgRunned(MainAppExe, false));
            BIN.AutoUpdateLog.LogObj.AddLog(LOG_MODE.INFO,
                string.Format("Check prog '{0}' wheather runned, Result is :{1}!",MainAppExe, Ret));
            return Ret;
        }

        private void btnRestartMain_Click(object sender, EventArgs e)
        {
            doFinishNormal();
        }
    }
}
